// TextureSynthetizeSimulator.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "CellScene.h"
#include "GeneratorGraph.h"
#include "Logger.h"
#include "CImg.h"
#include "MVCLib.h"
using namespace GraphCutLib;
#define IS_Log

#ifdef IS_Log
	GraphCutLib::Logger     logg;
#endif


void    copyImg(cimg_library::CImg<unsigned char>& srcImg,cimg_library::CImg<unsigned char>& desImg,int offsetX,int offsetY);

class RGB_EdgeWeightMgr : public EdgeWeightBase
{
public:
        
        virtual float getEdgeWeight(const NodeData& startNode,const NodeData& endNode);

        void            init(CellScene& inputScene,CellScene& interScene,cimg_library::CImg<unsigned char>& paintImg,cimg_library::CImg<unsigned char>& inputImg);

        std::vector<cimg_library::st_RGB<unsigned char> >       m_paintImg;
        std::vector<cimg_library::st_RGB<unsigned char> >       m_inputImg;

protected:
private:
};

void	impMVCClone(GraphCut<NodeData>& graphCut,cimg_library::CImg<unsigned char>* inputImg,cimg_library::CImg<unsigned char>* paintImg,CellScene& inputScene,
					CellScene& interScene)
{
	CellSceneBorderLink				sceneBorderLink;
	for (size_t i = 0; i < graphCut.m_sSubGragh.size(); ++i)
	{
		Node<NodeData>* node = graphCut.m_sSubGragh[i];

		for (size_t j = 0; j < node->edgeList.size(); ++j)
		{
			Edge<NodeData>& edge = node->edgeList[j];

			if(edge.endNode->color == NC_WHITE)
			{       
				sceneBorderLink.addBorderCellNode(CellNode(node->data.wIndex,node->data.hIndex));
				break;
			}
		}
	}

	sceneBorderLink.generatorNeighborInfo();

	CellLinkNode* headNode = sceneBorderLink.getWhiteColorLinkHead(inputScene);
	while (headNode != NULL)
	{
		CellSceneBorderLink::OrderBorderNodeLink& orderLink = sceneBorderLink.order(headNode,interScene);
		headNode = sceneBorderLink.getWhiteColorLinkHead(inputScene);
		const size_t orderLinkIndex = sceneBorderLink.m_orderBorderLinkList.size() - 1;

		CellScene       mvcCloneScene;
		mvcCloneScene.setSize(inputScene.m_width,inputScene.m_height,MVC_EMPTY_MASK);
		mvcCloneScene.setOffset(inputScene.m_offsetX,inputScene.m_offsetY);
		std::vector<ClonePixel<int> >   clonePixelList;
		
		GeneratorGraph gg;
        Graph<NodeData> graph;
        CellScene       tempInputScene;
        tempInputScene.setSize(inputScene.m_width,inputScene.m_height);
        tempInputScene.setOffset(inputScene.m_offsetX,inputScene.m_offsetY);
		//设置t region
		for (size_t i = 0; i < graphCut.m_tSubGragh.size(); ++i)
		{
			 Node<NodeData>* node = graphCut.m_tSubGragh[i];
			 CellNode interPos(node->data.wIndex,node->data.hIndex);
			 CellNode worldPos = interScene.localToWorldCellNode(interPos);
			 CellNode inputPos = inputScene.worldToLocalCellNode(worldPos);
			 tempInputScene.setMask(inputPos.x,inputPos.y,BUFFER_MASK_NORMAL);
		}
		//还需要把inputscene除interscene的部分也设置mask
		for (int y = 0; y < tempInputScene.m_height; ++y)
		{
			for (int x = 0; x < tempInputScene.m_width; ++x)
			{
				CellNode worldPos = tempInputScene.localToWorldCellNode(CellNode(x,y));
				CellNode interPos = interScene.worldToLocalCellNode(worldPos);
				//interscene可能是不规则形状，需要判断mask
				if(interScene.getMask(interPos.x,interPos.y) == BUFFER_MASK_EMPTY)
				{
					tempInputScene.setMask(x,y,BUFFER_MASK_NORMAL);					
				}				
			}
		}
        //把边界设置为t node		
		for (size_t j = 0; j < orderLink.size(); ++j)
		{       
			CellLinkNode* linkNode = sceneBorderLink.getLinkNodeByOrderIndex(j,orderLinkIndex);
			if(linkNode == NULL)
				continue;
			CellNode worldNode = interScene.localToWorldCellNode(linkNode->pos);
			CellNode localNode = inputScene.worldToLocalCellNode(worldNode);
			tempInputScene.setMask(localNode.x,localNode.y,BUFFER_MASK_T_NODE);
		}		
        
        gg.generatorGraph(graph,tempInputScene);

        graph.BFS(graph.tNode);

        const size_t nodeDis = 20;
       
        std::vector<Node<NodeData>* > nearNodeList;
		//find node satisfy dis between mindis and maxdis to mvcclone
        graph.findNearNode(2,nodeDis,nearNodeList);//目前得到nearNodeList是在inputscene空间

        float w = 0;
        clonePixelList.clear();
        for (size_t i = 0; i < nearNodeList.size(); ++i)
        {
            ClonePixel<int> clonePixel;
            w = (float)(nodeDis - nearNodeList[i]->dis) / (nodeDis - 2);
			w = std::min<float>(1.0f,w);
			w = std::max<float>(w,0);
            clonePixel.mvcWeight = w;
            CellNode inputPos = CellNode(nearNodeList[i]->data.wIndex,nearNodeList[i]->data.hIndex);
            CellNode worldPos = inputScene.localToWorldCellNode(inputPos);               
            //转换到inputscene空间
            clonePixel.srcPos = inputPos;
            //世界坐标
            clonePixel.desPos = worldPos;
            clonePixelList.push_back(clonePixel);
        }

		std::vector<CellNode> borderWorldPosList;
		//现在得到的borderNodeList是在intersectScene的空间，需要转换到inputScene的空间
		for (size_t j = 0; j < orderLink.size(); ++j)
		{
			CellLinkNode* linkNode = sceneBorderLink.getLinkNodeByOrderIndex(j,orderLinkIndex);
			if(linkNode == NULL)
				continue;
			CellNode worldPos = interScene.localToWorldCellNode(linkNode->pos);
			CellNode localPos = inputScene.worldToLocalCellNode(worldPos);
			//这里不能直接赋值，因为linkNode->pos.color值会被改写
			linkNode->pos.x = localPos.x;
			linkNode->pos.y = localPos.y;
			borderWorldPosList.push_back(worldPos);
		}

		MVCLib mvcLib;                                                                
		mvcLib.mvcClone(*inputImg,*paintImg,mvcCloneScene,interScene,sceneBorderLink,orderLinkIndex,clonePixelList,false);

		
		/*cimg_library::st_RGB<unsigned char> tempRGB(255,0,0);
		cimg_library::st_RGB<unsigned char> tempRGB2(0,255,0);
		for (size_t i = 0; i < borderWorldPosList.size(); ++i)
		{
			paintImg->RGB_set(tempRGB,borderWorldPosList[i].x,borderWorldPosList[i].y);
		}*/
		//copy mvclone pixel to img
		for (size_t i = 0; i < clonePixelList.size(); ++i)
		{
			ClonePixel<int>& clonePixel = clonePixelList[i];
			//clonePixel.outRGB.checkSame();
			cimg_library::st_RGB<int> tempRGB(clonePixel.outRGB.R,clonePixel.outRGB.R,clonePixel.outRGB.R);
			paintImg->RGB_set(tempRGB,clonePixel.desPos.x,clonePixel.desPos.y);
		}

	}
	
}

void	readOffsetFile(std::vector<CellNode>& offsetList)
{
	std::fstream fs("log.txt");
	std::string s;
	while(!fs.eof())
	{
		fs >> s;
	}

}

void	setWorldSceneMaskToImg(cimg_library::CImg<unsigned char>& img,CellScene& worldScene)
{
	cimg_library::st_RGB<unsigned char> sColor(255,0,0);
	for (int y = 0; y < worldScene.m_height; ++y)
	{
		for (int x = 0; x < worldScene.m_width; ++x)
		{
			if(worldScene.getMask(x,y) != BUFFER_MASK_EMPTY)
			{
				img.RGB_set(sColor,x,y);
			}
		}
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
		std::vector<CellNode>	offsetList;
		/*
		94 164
		247 132
		118 105
		*/
		/*offsetList.push_back(CellNode(63,355));
		offsetList.push_back(CellNode(186,291));
		offsetList.push_back(CellNode(60,252));
		offsetList.push_back(CellNode(238,212));

		offsetList.push_back(CellNode(119,164));
		offsetList.push_back(CellNode(284,133));
		offsetList.push_back(CellNode(190,91));*/
		//offsetList.push_back(CellNode(92,194));
		offsetList.push_back(CellNode(94,164));
		offsetList.push_back(CellNode(247,132));
		offsetList.push_back(CellNode(118,105));
        {
            using namespace cimg_library;

            CellScene       paintScene;
            paintScene.setSize(512,512);

            CImg<unsigned char> img(512,512,1,3);
            CImg<unsigned char> img2("1.bmp");
            CImg<unsigned char> img3("2.bmp");
            CImg<unsigned char>*    inputImg = &img2;
            CImgDisplay main_disp(img,"Click a point");

            bool    fillRedGreenColor = false;
		//	std::vector<ClonePixel<int> >   clonePixelList;
			std::vector<CellNode>			borderWorldPosList;
			int mouseCount = 0;
			float rotateAngle = 0;
			bool getOffsetFromFile = true;
			CellScene       inputScene;
			CellScene		interScene;
			Graph<NodeData>			graph;
			GraphCut<NodeData>      graphCut(&graph);

            while (!main_disp.is_closed())
            {
                    
				if ((main_disp.button()&1) && main_disp.mouse_y()>=0) 
                {
                    int offsetX = main_disp.mouse_x();
                    int offsetY = main_disp.mouse_y();

					if(getOffsetFromFile && mouseCount< offsetList.size())
					{
						offsetX = offsetList[mouseCount].x;
						offsetY = offsetList[mouseCount].y;
					}
#ifdef IS_Log
					//log input offset
					std::stringstream ss;
					ss << offsetX << " " << offsetY;
					Logger::getInstance()->log(ss.str());
#endif
					

					/*CImg<unsigned char> imgRotate = img2.get_rotate((mouseCount++) * 90);
					inputImg = &imgRotate;*/
					if((mouseCount) % 2 == 0)
						inputImg = &img2;
					else
						inputImg = &img3;
              
                    inputScene.m_offsetX = offsetX;
                    inputScene.m_offsetY = offsetY;
    
                    inputScene.setSize(inputImg->_width,inputImg->_height,BUFFER_MASK_NORMAL);
                    inputScene.generatorRandomValue();

                    
                    interScene = paintScene.importData(inputScene);

                    if(interScene.m_width == 0)
                    {
                        copyImg(*inputImg,img,offsetX,offsetY);                                 
                    }
                    else
                    {
                        for(int y = 0; y < interScene.m_height; ++y)
                        {
                            for (int x = 0; x < interScene.m_width; ++x)
                            {
                                CellNode worldNode = interScene.localToWorldCellNode(CellNode(x,y));
                                st_RGB<unsigned char> rgb1 = img.RGB_at(worldNode.x,worldNode.y);
                                CellNode localNode = inputScene.worldToLocalCellNode(worldNode);
                                st_RGB<unsigned char> rgb2 = inputImg->RGB_at(localNode.x,localNode.y);
                                
                                int value = abs(rgb1.R - rgb2.R) + abs(rgb1.G - rgb2.G) + abs(rgb1.B - rgb2.B);
                                interScene.setValue(x,y,value);
                            }
                        }

                        RGB_EdgeWeightMgr rgbEdgeWeight;
                        rgbEdgeWeight.init(inputScene,interScene,img,*inputImg);

                        GeneratorGraph gg;    
						graph.release();
                        gg.generatorGraph(graph,interScene,&rgbEdgeWeight);

						graphCut.release();
						graphCut.setGraph(&graph);
                        graphCut.fordfulkerson();
                        st_RGB<unsigned char> sColor(255,0,0);
                        st_RGB<unsigned char> tColor(0,255,0);
                                             
                        CImg<unsigned char> tempImg(img);
                        copyImg(*inputImg,img,offsetX,offsetY);

                        for (size_t i = 0; i < graphCut.m_sSubGragh.size(); ++i)
                        {
                            NodeData& data = graphCut.m_sSubGragh[i]->data;
                            CellNode worldNode = interScene.localToWorldCellNode(CellNode(data.wIndex,data.hIndex));
                            st_RGB<unsigned char> color = tempImg.RGB_at(worldNode.x,worldNode.y); 

							//for debug
							if(interScene.isInsideLocalCoord(CellNode(data.wIndex,data.hIndex)) == false)
								int ii = 0;

                            if(fillRedGreenColor)
                                img.RGB_set(sColor,worldNode.x,worldNode.y);
                            else    
                                img.RGB_set(color,worldNode.x,worldNode.y);
                        }

						
                        
                        if(fillRedGreenColor)
                        {
                            for (size_t i = 0; i < graphCut.m_tSubGragh.size(); ++i)
                            {
                                NodeData& data = graphCut.m_tSubGragh[i]->data;
                                CellNode worldNode = interScene.localToWorldCellNode(CellNode(data.wIndex,data.hIndex));
                                CellNode localNode = inputScene.worldToLocalCellNode(worldNode);
                                st_RGB<unsigned char> color = inputImg->RGB_at(localNode.x,localNode.y);
                                img.RGB_set(tColor,worldNode.x,worldNode.y);
                            }
                        }
                            
                    }
					mouseCount++;
                    main_disp.display(img);

					impMVCClone(graphCut,inputImg,&img,inputScene,interScene);
                }  
                else if(main_disp.button()&2)
                {							
					//impMVCClone(graphCut,inputImg,&img,inputScene,interScene);
					//测试patin mask是否设置正确
					//setWorldSceneMaskToImg(img,paintScene);
					
					 main_disp.display(img);
                }
                main_disp.wait();
            }
            img.display();
        }

        return 0;
}
using namespace cimg_library;
void    copyImg(CImg<unsigned char>& srcImg,CImg<unsigned char>& desImg,int offsetX,int offsetY)
{
        for (int i = 0; i < srcImg._height; ++i)
        {
                for (int j = 0; j < srcImg._width; ++j)
                {
                        if(j + offsetX >= desImg._width)
                                continue;
                        if(i + offsetY >= desImg._height)
                                continue;

                        st_RGB<unsigned char> rgb = srcImg.RGB_at(j,i);
                        desImg.RGB_set(rgb,offsetX + j,offsetY + i);
                }
        }
}

void    RGB_EdgeWeightMgr::init(GraphCutLib::CellScene& inputScene,GraphCutLib::CellScene& interScene,CImg<unsigned char>& paintImg,CImg<unsigned char>& inputImg)
{
        const size_t bufferSize = interScene.m_width * interScene.m_height;
        m_paintImg.clear();
        m_inputImg.clear();

        for (int y = 0; y < interScene.m_height; ++y)
        {
                for (int x = 0;x < interScene.m_width; ++x)
                {
                        size_t localIndex = y * interScene.m_width + x;
                        CellNode        worldNode = interScene.localToWorldCellNode(CellNode(x,y));
                        CellNode        inputLocalNode = inputScene.worldToLocalCellNode(worldNode);

                        m_paintImg.push_back(paintImg.RGB_at(worldNode.x,worldNode.y));
                        m_inputImg.push_back(inputImg.RGB_at(inputLocalNode.x,inputLocalNode.y));
                }
        }
}

float           RGB_EdgeWeightMgr::getEdgeWeight(const GraphCutLib::NodeData& startNode,const GraphCutLib::NodeData& endNode)
{
        st_RGB<unsigned char> sRGB = m_paintImg[startNode.nodeIndex];
        st_RGB<unsigned char> tRGB = m_inputImg[startNode.nodeIndex];

        float value = abs(sRGB.R - tRGB.R) + abs(sRGB.G - tRGB.G) + abs(sRGB.B - tRGB.B);
        return value;
}